#include "os_cfg.h"

    .text
    .extern kernel_init init_main
    .global _start
    //这里的_start函数实际上原型是这样void _start(boot_info_t * boot_info)
_start:
    push %ebp;
    mov %esp,%ebp;
    mov 0x8(%ebp),%eax;


    #mov 0x4(%esp),%eax;

    push %eax;
    call kernel_init

    jmp $KERNEL_SELECTOR_CS,$gdt_reload
gdt_reload:
    mov $KERNEL_SELECTOR_DS,%ax
	mov %ax,%ds
	mov %ax,%ss
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs

    //重新设置栈空间
    mov $(stack+KERNEL_STACK_SIZE),%esp

    call init_main

    .bss
.comm stack,KERNEL_STACK_SIZE

//汇编宏函数定义
.macro exception_handler name num with_err_code
    .text
    .extern do_handler_\name
    .global exception_handler_\name
    //中断处理程序需要对程序现场进行保护
exception_handler_\name:
    .if \with_err_code == 0
        push $0
    .endif
    push $\num
    pusha
    push %ds
    push %es
    push %fs
    push %gs

    push %esp
    call do_handler_\name
    add $(1*4),%esp

    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa

    add $(2*4),%esp
    
    iret
.endm

exception_handler unknown, -1, 0
exception_handler divide, 0, 0
exception_handler debug, 1, 0
exception_handler NMI, 2, 0
exception_handler breakpoint, 3, 0
exception_handler overflow, 4, 0
exception_handler bound_range, 5, 0
exception_handler invalid_opcode, 6, 0
exception_handler device_unavailable, 7, 0
exception_handler double_fault, 8, 1
exception_handler invalid_tss, 10, 1
exception_handler segment_not_present, 11, 1
exception_handler stack_segment_fault, 12, 1
exception_handler general_protection, 13, 1
exception_handler page_fault, 14, 1
exception_handler fpu_error, 16, 0
exception_handler alignment_check, 17, 1
exception_handler machine_check, 18, 0
exception_handler simd_exception, 19, 0
exception_handler virtual_exception, 20, 0
exception_handler control_exception, 21, 1

exception_handler timer, 0x20, 0
exception_handler keyboard, 0x21, 0
exception_handler ide_primary, 0x2E, 0

    .global exception_handler_syscall
    .extern do_handler_syscall
exception_handler_syscall:
    // 保存前一任务的状态
	pusha
	push %ds
	push %es
	push %fs
	push %gs
	pushf

	// 使用内核段寄存器，避免使用应用层的
	mov $(KERNEL_SELECTOR_DS), %eax
	mov %eax, %ds
	mov %eax, %es
	mov %eax, %fs
	mov %eax, %gs

    // 调用处理函数
    mov %esp, %eax
    push %eax
	call do_handler_syscall
	add $4, %esp

    // 再切换回来
	popf
	pop %gs
	pop %fs
	pop %es
	pop %ds
	popa
	
	// 5个参数，加上5*4，不加会导致返回时ss取不出来，最后返回出现问题
    retf $(5*4)    // CS发生了改变，需要使用远跳转

